package com.otp.webapp.action;

import java.io.IOException;
import java.io.Serializable;
import java.util.Iterator;
import java.util.Set;

import org.apache.myfaces.custom.fileupload.UploadedFile;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFRichTextString;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.appfuse.Constants;
import org.appfuse.model.Address;
import org.appfuse.model.Organization;
import org.appfuse.model.User;
import org.appfuse.service.RoleManager;
import org.appfuse.service.UserExistsException;
import org.springframework.mail.MailException;
import org.springframework.security.access.AccessDeniedException;

import com.otp.exceptions.PermissionsToTestTemplateNotGrantedException;
import com.otp.exceptions.PermissionsToUserNotGrantedException;
import com.otp.exceptions.UnknownExternalNameException;
import com.otp.model.test.instance.TestInstance;
import com.otp.model.test.instance.TestInstanceState;
import com.otp.model.test.template.TestTemplate;
import com.otp.service.instance.TestInstanceManager;
import com.otp.service.instance.User1Manager;
import com.otp.service.util.RandomString;
import com.otp.webapp.util.RequestUtil;


public class FileUpload extends BasePage implements Serializable {
	private static final long serialVersionUID = 6932775516007291334L;
	private UploadedFile file;
	private String name;
	private TestInstanceManager testInstanceManager;
	private boolean userExists = true;
	private RoleManager roleManager;
	private User1Manager user1Manager;
	private String templateExternalName;



	public void setUser1Manager(User1Manager user1Manager) {
		this.user1Manager = user1Manager;
	}
	public void setRoleManager(RoleManager roleManager) {
		this.roleManager = roleManager;
	}

	public void setTestInstanceManager(TestInstanceManager testInstancesManager) {
		this.testInstanceManager = testInstancesManager;
	}


	public UploadedFile getFile() {
		return file;
	}

	public void setFile(UploadedFile file) {
		this.file = file;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String upload() throws IOException {

		boolean statusOk=true;
		
		// get hold of the file
		POIFSFileSystem fileSystem = null;
		try {
			fileSystem = new POIFSFileSystem(file.getInputStream());

			HSSFWorkbook workBook = new HSSFWorkbook(fileSystem);
			HSSFSheet sheet = workBook.getSheetAt(0);

			@SuppressWarnings("unchecked")
			Iterator<HSSFRow> rows = sheet.rowIterator();

			// Ignore the header row
			if (rows.hasNext())
				rows.next();

			while (rows.hasNext()) {
				HSSFRow row = rows.next();
				// display row number in the console.
				//System.out.println("Current Row No.: " + row.getRowNum());
				// once get a row its time to iterate through cells.
				@SuppressWarnings("unchecked")
				Iterator<HSSFCell> cells = row.cellIterator();
				// Create users
				String firstName = null;
				String lastName = null;
				String email = null;
				templateExternalName = null;
				String address=null;
				String city=null;
				String State=null;
				String zip=null;
				String country=null;
				boolean showResult = false;
				String username = null;
				String password = null;
				boolean sendEmail = false;

				while (cells.hasNext()) {
					HSSFCell cell = cells.next();

					@SuppressWarnings("deprecation")
					short cellNum = cell.getCellNum();
					switch (cellNum) {
					case 0: {
						HSSFRichTextString richTextString = cell
								.getRichStringCellValue();
						firstName = richTextString.getString().trim();
						break;
					}
					case 1: {
						HSSFRichTextString richTextString = cell
								.getRichStringCellValue();
						lastName = richTextString.getString().trim();
						break;
					}
					case 2: {
						HSSFRichTextString richTextString = cell
								.getRichStringCellValue();
						email = richTextString.getString().trim();
						break;
					}
					case 3: {
						HSSFRichTextString richTextString = cell
								.getRichStringCellValue();
						templateExternalName = richTextString.getString().trim();
						break;
					}
					case 4: {
						HSSFRichTextString richTextString = cell
								.getRichStringCellValue();
						address = richTextString.getString().trim();
						break;
					}
					case 5: {
						HSSFRichTextString richTextString = cell
								.getRichStringCellValue();
						city = richTextString.getString().trim();
						break;
					}
					case 6: {
						HSSFRichTextString richTextString = cell
								.getRichStringCellValue();
						State = richTextString.getString().trim();
						break;
					}
					/*case 7: {
							HSSFRichTextString richTextString = cell
									.getRichStringCellValue();
							zip = richTextString.getString();
							break;
						}*/
					case 8: {
						HSSFRichTextString richTextString = cell
								.getRichStringCellValue();
						country = richTextString.getString().trim();
						break;
					}
					case 9: {
						HSSFRichTextString richTextString = cell
								.getRichStringCellValue();
						showResult = "Y".equals(richTextString.getString());
						break;
					}
					case 10: {
						HSSFRichTextString richTextString = cell
								.getRichStringCellValue();
						username = richTextString.getString().trim();
						break;
					}
					case 11: {
						HSSFRichTextString richTextString = cell
								.getRichStringCellValue();
						password = richTextString.getString();
						break;
					}
					case 12: {
						HSSFRichTextString richTextString = cell
								.getRichStringCellValue();
						sendEmail = "Y".equals(richTextString.getString());
						break;
					}
					default: {
						break;
					}
					}
				}
				
				User assignedUser = createOrLoadUser(username, password, firstName,lastName,email,address,State,country,zip,city);
				Organization adminOrg=getLoggedUserOrganization();
				Organization userOrg=assignedUser.getOrgs();
				if(!isSuperAdminUser()&&adminOrg.getObjectId()!=userOrg.getObjectId())
					throw(new PermissionsToUserNotGrantedException("")); //Trying to overcome permissions
				
				
				TestTemplate testTemplate = testInstanceManager.fetchTemplate(templateExternalName);
				if(testTemplate==null) throw new UnknownExternalNameException("Unknown external name");
				
				Set<TestTemplate> tts = assignedUser.getOrgs().getTestTemplates();
				boolean foundMatch = false;
				for(TestTemplate tt: tts)
					if(tt.getObjectId()==testTemplate.getObjectId()){
						foundMatch=true;
						break;
					}
				if(!foundMatch) throw new PermissionsToTestTemplateNotGrantedException("");
				
				assignTestToUser(assignedUser,testTemplate,showResult);

				if(sendEmail){
					sendMail(assignedUser,userExists);
				}
			}
		}catch (UnknownExternalNameException e){
			e.printStackTrace();
			addError("upload.test.template.not.exists", new Object[]{templateExternalName});
			statusOk = false;	
		}catch (PermissionsToTestTemplateNotGrantedException e){
			e.printStackTrace();
			addError("upload.test.template.no.permissions", new Object[]{templateExternalName});
			statusOk = false;
		}catch (PermissionsToUserNotGrantedException e){
			e.printStackTrace();
			Organization adminOrg=getLoggedUserOrganization();
			addError("upload.user.exists.no.permissions", new Object[]{adminOrg.getOrganizationName()});
			statusOk = false;
		}catch (MailException me){
			me.printStackTrace();
			addError(me.getMostSpecificCause().getMessage());
		}catch (Exception e){
			e.printStackTrace();
			addError("upload.file.notwellformed");
			statusOk=false;
		}
		if(statusOk) addMessage("upload.success");
		return null;
	}

	private void sendMail(User newUser, Boolean existingUser) {
		// Prepare Mail
		if(!existingUser){
			try {
				message.setSubject(getText("signup.email.subject.new.test"));
				setTemplateName("accountCreatedandAssigned.vm");
//				sendUserMessage(newUser, getText("signup.email.message.new.test"),
//						RequestUtil.getAppURL(getRequest()));
				sendUserMessage(newUser, new String[0], RequestUtil.getAppURL(getRequest()));
			} catch (MailException me) {
				addError(me.getMostSpecificCause().getMessage());
			}
		}else{
			try {
				message.setSubject(getText("signup.email.subject.test"));
				setTemplateName("assignTestUser.vm");
//				sendUserMessage(newUser, getText("signup.email.message.test"),
//						RequestUtil.getAppURL(getRequest()));
				sendUserMessage(newUser, new String[0], RequestUtil.getAppURL(getRequest()));
			} catch (MailException me) {
				addError(me.getMostSpecificCause().getMessage());
			}

		}

	}

	private void assignTestToUser(User user, TestTemplate testTemplate, boolean showResult) {
		
		TestInstance instance = new TestInstance();
		instance.setAppUser(user);
		instance.setTestTemplate(testTemplate);
		instance.setShowResult(showResult);
		instance.setTestScoringAlgorithm(testTemplate.getDefaultScoringAlgorithm());

		TestInstanceState state = new TestInstanceState();
		state.setObjectId(new Long(1001));
		state.setState("READY");
		instance.setTestInstanceState(state);
		testInstanceManager.save(instance);
	}


	private User createOrLoadUser(String username, String password, String firstName,
			String lastName, String email, String address, String state, String country, String zip, String city) {
		User user = null;

		int emailStatus;//0 if null, 1 if in the DB, 2 if new
		int usernameStatus;//as above;
		User emailUser=null;
		User usernameUser=null;

		if(email==null||email.isEmpty()) emailStatus=0;
		else{
			emailUser=user1Manager.getUserByEmail(email);
			if(emailUser!=null) emailStatus=1;
			else emailStatus=2;
		}

		if(username==null||username.isEmpty()) usernameStatus=0;
		else{
			usernameUser=user1Manager.getUserByUsername(username);
			if(usernameUser!=null) usernameStatus=1;
			else usernameStatus=2;
		}

		//MAIN CODE 
		//look above for definitions for emailStatus and usernameStatus
		if(emailStatus==0){
			if(usernameStatus==0) {addMessage("errors.username.email.null"); return null;}
			if(usernameStatus==2) {addMessage("errors.username.new.email.null"); return null;}
			user=usernameUser;
			userExists=true;			
		}
		else if(emailStatus==1){
			user=emailUser;
			userExists=true;
		}
		else if(emailStatus==2){
			if(usernameStatus==0){
				username=email;
				password=RandomString.genStr();
				userExists=false;
			}
			else if(usernameStatus==1){
				user=usernameUser;
				userExists=true;
			}
			else if(usernameStatus==2){
				if(password==null||password.isEmpty()) password=RandomString.genStr();
				userExists=false;
			}
		}

		if(userExists) return user;
		else{
			User newUser = new User();
			newUser.setUsername(username);
			newUser.setFirstName(firstName);
			newUser.setLastName(lastName);
			newUser.setEmail(email);
			newUser.setPassword(password);
			newUser.setConfirmPassword(password);
			newUser.setEnabled(true);

			newUser.addRole(roleManager.getRole(Constants.USER_ROLE));

			Address add = new Address();
			add.setAddress(address);
			add.setCity(city);
			add.setCountry(country);
			add.setPostalCode(zip);
			add.setProvince(state);
			newUser.setAddress(add);
			
			
			newUser.setOrgs(getLoggedUserOrganization());

			try {
				user = userManager.saveUser(newUser);
			}catch (AccessDeniedException ade){
				// thrown by UserSecurityAdvice configured in aop:advisor userManagerSecurity 
				log.warn(ade.getMessage());;
				ade.printStackTrace();
				return null; 
			} catch (UserExistsException e) {
				e.printStackTrace();
				return null;
			}
			return user;
		}
	}

/*	public String uploadOld() throws IOException {

		HttpServletRequest request = getRequest();

		// write the file to the filesystem
		// the directory to upload to
		String uploadDir = getServletContext().getRealPath("/resources") + "/"
				+ request.getRemoteUser() + "/";

		// Create the directory if it doesn't exist
		File dirPath = new File(uploadDir);

		if (!dirPath.exists()) {
			dirPath.mkdirs();
		}

		// retrieve the file data
		InputStream stream = file.getInputStream();
		String filename = file.getName();

		// APF-946: Canoo Web Tests R_1702 sets full path as name instead of
		// only file name
		if (filename.indexOf("/") > -1) {
			filename = filename.substring(filename.lastIndexOf("/") + 1);
		}

		// APF-758: Fix for Internet Explorer's shortcomings
		if (filename.indexOf("\\") != -1) {
			int slash = filename.lastIndexOf("\\");
			if (slash != -1) {
				filename = filename.substring(slash + 1);
			}
			// Windows doesn't like /'s either
			int slash2 = filename.lastIndexOf("/");
			if (slash2 != -1) {
				filename = filename.substring(slash2 + 1);
			}
			// In case the name is C:foo.txt
			int slash3 = filename.lastIndexOf(":");
			if (slash3 != -1) {
				filename = filename.substring(slash3 + 1);
			}
		}

		// write the file to the file specified
		OutputStream bos = new FileOutputStream(uploadDir + filename);
		int bytesRead;
		byte[] buffer = new byte[8192];

		while ((bytesRead = stream.read(buffer, 0, 8192)) != -1) {
			bos.write(buffer, 0, bytesRead);
		}

		bos.close();

		// close the stream
		stream.close();

		// place the data into the request for retrieval on next page
		request.setAttribute("friendlyName", name);
		request.setAttribute("fileName", filename);
		request.setAttribute("contentType", file.getContentType());
		request.setAttribute("size", file.getSize() + " bytes");
		request.setAttribute("location", dirPath.getAbsolutePath()
				+ Constants.FILE_SEP + filename);

		String link = request.getContextPath() + "/resources" + "/"
				+ request.getRemoteUser() + "/";
		request.setAttribute("link", link + filename);

		return "success";
	}*/
}